/*
7-163 口罩发放
分数 25
作者 DAI, Longao
单位 杭州百腾教育科技有限公司

为了抗击来势汹汹的  COVID19
新型冠状病毒，全国各地均启动了各项措施控制疫情发展，其中一个重要的环节是口罩的发放。

某市出于给市民发放口罩的需要，推出了一款小程序让市民填写信息，方便工作的开展。小程序收集了各种信息，包括市民的姓名、身份证、身体情况、提交时间等，但因为数据量太大，需要根据一定规则进行筛选和处理，请你编写程序，按照给定规则输出口罩的寄送名单。
输入格式:

输入第一行是两个正整数 D 和 P（1≤D,P≤30），表示有 D
天的数据，市民两次获得口罩的时间至少需要间隔 P 天。

接下来 D 块数据，每块给出一天的申请信息。第 i
块数据（i=1,⋯,D）的第一行是两个整数 Ti​ 和
Si​（1≤Ti​,Si​≤1000），表示在第 i 天有 Ti​
条申请，总共有 Si​ 个口罩发放名额。随后 Ti​
行，每行给出一条申请信息，格式如下：

姓名 身份证号 身体情况 提交时间

给定数据约束如下：

    姓名 是一个长度不超过 10 的不包含空格的非空字符串；
    身份证号 是一个长度不超过 20 的非空字符串；
    身体情况 是 0 或者 1，0 表示自觉良好，1 表示有相关症状；
    提交时间 是 hh:mm，为24小时时间（由 00:00 到 23:59。例如
09:08。）。注意，给定的记录的提交时间不一定有序； 身份证号
各不相同，同一个身份证号被认为是同一个人，数据保证同一个身份证号姓名是相同的。

能发放口罩的记录要求如下：

    身份证号 必须是 18 位的数字（可以包含前导0）；
    同一个身份证号若在第 i 天申请成功，则接下来的 P 天不能再次申请。也就是说，若第 i 天申请成功，则等到第 i+P+1 天才能再次申请；
    在上面两条都符合的情况下，按照提交时间的先后顺序发放，直至全部记录处理完毕或 Si​ 个名额用完。如果提交时间相同，则按照在列表中出现的先后顺序决定。

输出格式:

对于每一天的申请记录，每行输出一位得到口罩的人的姓名及身份证号，用一个空格隔开。顺序按照发放顺序确定。

在输出完发放记录后，你还需要输出有合法记录的、身体状况为 1
的申请人的姓名及身份证号，用空格隔开。顺序按照申请记录中出现的顺序确定，同一个人只需要输出一次。
输入样例:

4 2
5 3
A 123456789012345670 1 13:58
B 123456789012345671 0 13:58
C 12345678901234567 0 13:22
D 123456789012345672 0 03:24
C 123456789012345673 0 13:59
4 3
A 123456789012345670 1 13:58
E 123456789012345674 0 13:59
C 123456789012345673 0 13:59
F F 0 14:00
1 3
E 123456789012345674 1 13:58
1 1
A 123456789012345670 0 14:11

输出样例:

D 123456789012345672
A 123456789012345670
B 123456789012345671
E 123456789012345674
C 123456789012345673
A 123456789012345670
A 123456789012345670
E 123456789012345674

样例解释：

输出中，第一行到第三行是第一天的部分；第四、五行是第二天的部分；第三天没有符合要求的市民；第六行是第四天的部分。最后两行按照出现顺序输出了可能存在身体不适的人员。

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 30 * 1001

typedef struct RequestData RequestData;
struct RequestData {
    char name[11];
    char id[21];
    int health;
    int time;
    int order; // 申请顺序
};

// 数据列表, C缺乏必要的数据结构，只能自己实现，囧
typedef struct RequestDataList RequestDataList;
struct RequestDataList {
    RequestData *data[MAX];
    int lastIdx;
};

// 直接添加数据
void addList(RequestDataList *list, RequestData *data) {
    list->data[list->lastIdx++] = data;
}

void resetList(RequestDataList *list) { list->lastIdx = 0; }

// 判断list中是否包括id为 data->id 的数据
int contains(RequestDataList *list, RequestData *data, int startIdx) {
    for (int i = startIdx; i < list->lastIdx; i++) {
        if (strcmp(list->data[i]->id, data->id) == 0) {
            return 1;
        }
    }
    return 0;
}

int compare(const void *a, const void *b) {
    RequestData **ra = (RequestData **)a;
    RequestData **rb = (RequestData **)b;
    // 先比较时间，再比较申请顺序
    int t = (*ra)->time - (*rb)->time;
    return t != 0 ? t : (*ra)->order - (*rb)->order;
}

int validId(RequestData *d) {
    if (strlen(d->id) != 18) {
        return 0;
    }
    // 检查身份证号是否全为数字
    for (int i = 0; i < 18; i++) {
        if (d->id[i] < '0' || d->id[i] > '9') {
            return 0;
        }
    }
    return 1;
}

RequestData *inputData(int order) {
    RequestData *d = (RequestData *)malloc(sizeof(RequestData));
    int h, m;
    scanf("%s %s %d %d:%d", d->name, d->id, &(d->health), &h, &m);
    d->time = h * 100 + m;
    d->order = order;
    return d;
}

int main() {
    int d, p;
    scanf("%d %d", &d, &p);

    // 当前批次符合发放标准的申请数据
    RequestDataList data;
    data.lastIdx = 0;
    // 已发放的数据
    RequestDataList issuedList;
    issuedList.lastIdx = 0;
    // 记录每个批次的发放数量，用于计算检查点
    int issuedCount[30] = {0};

    // 不良健康数据
    RequestDataList unhealthyList;
    unhealthyList.lastIdx = 0;

    int checkIdx = 0;
    for (int i = 0; i < d; i++) {
        // 重置当前数据
        resetList(&data);

        // 若第 i 天申请成功，则等到第 i+P+1 天才能再次申请
        // 计算要检查的发放记录的开始位置，在p天前的发放记录不需要检查
        if (i >= p + 1) {
            checkIdx += issuedCount[i - p - 1];
        }

        int t, s;
        scanf("%d %d", &t, &s);
        for (int j = 0; j < t; j++) {
            // 暂时不管释放内存
            RequestData *d = inputData(j);
            if (validId(d)) {
                // 添加到当前批次数据
                addList(&data, d);
                if (d->health == 1 && !contains(&unhealthyList, d, 0)) {
                    addList(&unhealthyList, d);
                }
            }
        }
        // 符合发放标准的数据排序，按照时间和申请顺序
        t = data.lastIdx;
        qsort(data.data, t, sizeof(RequestData *), compare);
        // 发放口罩
        for (int j = 0; j < t && s > 0; j++) {
            if (contains(&issuedList, data.data[j], checkIdx)) {
                continue;
            }
            printf("%s %s\n", data.data[j]->name,
                   data.data[j]->id);
            addList(&issuedList, data.data[j]);
            s--;
            issuedCount[i]++;
        }
    }
    // printf("\n");
    for (int i = 0; i < unhealthyList.lastIdx; i++) {
        printf("%s %s\n", unhealthyList.data[i]->name,
               unhealthyList.data[i]->id);
    }
    return 0;
}